/*
 * Licensed to the 南京汇海交通科技有限公司
 *
 * Copyright (c) 2025.
 * All rights reserved.
 *
 * 本软件属南京汇海交通科技有限公司所有，在未获得南京汇海交通科技有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.chframework.common.thread;

import com.chframework.common.exception.ApplicationException;
import com.chframework.common.exception.UtilityException;
import com.chframework.common.thread.threadpool.ThreadPoolHelper;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncTask;

import java.util.concurrent.Callable;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.Future;
import java.util.function.Supplier;

/**
 * spring-mvc中异步执行工具类 - 在Controller层 将正常HTTP请求改造为异步请求
 * <p>
 * 说明：
 * - java8中 引入 CompletableFuture<T>  用于 Java 中的异步编程。
 * 异步编程是一种编写非阻塞代码的方法，方法是在与主应用程序线程不同的线程上运行任务，并通知主线程其进度、完成或失败。
 * <p>
 * - java中 使用reactor框架，实现异步非阻塞编程。
 * <p>
 * - 在Servlet 3.0 之后，其也支持异步非阻塞请求。
 * <p>
 * - SpringBoot 本身即是 对 Spring + SpringMVC(本质是Servlet服务) + Tomcat/Jetty/Undertow 的集成，
 * 所以，在SpringBoot2.0之后，基于SpringBoot构建的Servlet服务，已经支持 基于CompletableFuture<T> 与 Mono<T> 的异步请求。
 */
public class AsyncHelper {

    /**
     * 用于Controller层接口异步改造：
     * ■ 返回 java.util.concurrent.Callable<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.WebAsyncTask<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.DeferredResult<T> 类型
     * ■ 返回 java.util.concurrent.CompletableFuture<T> 类型
     * ■ 返回 reactor.core.publisher.Mono<T> 类型
     */
    public static <T> WebAsyncTask<T> buildTask(Supplier<T> supplier) {
        Callable<T> callable = supplier::get;
        return new WebAsyncTask<>(callable);
    }

    /**
     * 用于Controller层接口异步改造：
     * ■ 返回 java.util.concurrent.Callable<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.WebAsyncTask<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.DeferredResult<T> 类型
     * ■ 返回 java.util.concurrent.CompletableFuture<T> 类型
     * ■ 返回 reactor.core.publisher.Mono<T> 类型
     */
    public static <T> WebAsyncTask<T> buildTask(Callable<T> callable) {
        return new WebAsyncTask<>(callable);
    }

    /**
     * 用于Controller层接口异步改造：
     * ■ 返回 java.util.concurrent.Callable<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.WebAsyncTask<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.DeferredResult<T> 类型
     * ■ 返回 java.util.concurrent.CompletableFuture<T> 类型
     * ■ 返回 reactor.core.publisher.Mono<T> 类型
     */
    public static <T> DeferredResult<T> buildResult(Supplier<T> supplier) {
        DeferredResult<T> result = new DeferredResult<>();
        ForkJoinTask<Boolean> forkJoinTask = ThreadPoolHelper.commonPool().submit(() -> result.setResult(supplier.get()));
        if (forkJoinTask.isCompletedAbnormally()) {
            throw new ApplicationException(forkJoinTask.getException());
        }
        return result;
    }

    /**
     * 用于Controller层接口异步改造：
     * ■ 返回 java.util.concurrent.Callable<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.WebAsyncTask<T> 类型
     * ■ 返回 org.springframework.web.context.request.async.DeferredResult<T> 类型
     * ■ 返回 java.util.concurrent.CompletableFuture<T> 类型
     * ■ 返回 reactor.core.publisher.Mono<T> 类型
     */
    public static <T> DeferredResult<T> buildResult(Callable<T> task) {
        DeferredResult<T> result = new DeferredResult<>();
        ForkJoinTask<Boolean> forkJoinTask = ThreadPoolHelper.commonPool().submit(() -> result.setResult(task.call()));
        if (forkJoinTask.isCompletedAbnormally()) {
            throw new ApplicationException(forkJoinTask.getException());
        }
        return result;
    }

    /**
     * 通过异步的方式 调用 同步方法，有返回值
     */
    public static <T> Future<T> convert(Callable<T> task) throws UtilityException {
        try {
            return new AsyncResult<>(task.call());
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 通过异步的方式 调用 同步方法，无返回值
     */
    public static Future<Void> convert(Runnable task) {
        task.run();
        return new AsyncResult<>(null);
    }

}
